package ua.kpi.ipsa.expert.api.adminpanel;

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.rmi.*;

import javax.swing.*;
import javax.swing.event.*;

import net.miginfocom.swing.*;
import ua.kpi.ipsa.expert.api.net.*;

import javax.swing.border.BevelBorder;

/**
 * 
 * @author doctorpro
 * 
 */
public class AdminpanelGui extends JPanel {

	private JLabel connectionStateIcon;
	private JLabel connectionStateText;
	private JLabel connectionLabel;
	private JLabel serverStateText;
	private JLabel serverStateIcon;
	private JLabel stateLabel;

	private ImageIcon greenCircle, redCircle, yellowCircle;
	private JButton connectButton;

	private ConnectionApplicationListener applicationListener;
	private JTabbedPane tabbedPane;
	private JPanel panel_1;
	private JPanel panel_2;
	private JTextField filterField;
	private JButton btnAdd;
	private JButton btnDelete;
	private JScrollPane scrollPane;
	private JList<RemoteUser> list;
	private JPanel panel_4;
	private JButton btnKick;
	private JButton btnShutdown;
	
	private Filterable filterable;

	//
	private boolean connected = false;
	private boolean serverOnline = false;

	//
	AdminsConsole adminConsole;

	/**
	 * Create the panel.
	 */
	public AdminpanelGui(ConnectionApplicationListener applicationListener) {

		GridBagLayout gridBagLayout = new GridBagLayout();
		gridBagLayout.columnWidths = new int[] { 229, 0, 182, 0 };
		gridBagLayout.rowHeights = new int[] { 46, 0, 0, 0 };
		gridBagLayout.columnWeights = new double[] { 1.0, 1.0, 0.0,
				Double.MIN_VALUE };
		gridBagLayout.rowWeights = new double[] { 0.0, 0.0, 1.0,
				Double.MIN_VALUE };
		setLayout(gridBagLayout);

		JPanel panel = new JPanel();
		panel.setLayout(new MigLayout("", "[][][][grow]", "[][]"));

		stateLabel = new JLabel("Server state:");
		panel.add(stateLabel, "cell 0 0,alignx left");

		serverStateIcon = new JLabel("");
		panel.add(serverStateIcon, "cell 1 0");

		serverStateText = new JLabel("unknown");
		panel.add(serverStateText, "cell 2 0,alignx left");

		connectionLabel = new JLabel("Connection:");
		panel.add(connectionLabel, "cell 0 1,alignx left");

		connectionStateIcon = new JLabel("");
		panel.add(connectionStateIcon, "cell 1 1");

		connectionStateText = new JLabel("not connected");
		panel.add(connectionStateText, "cell 2 1,alignx left");
		GridBagConstraints gbc_panel = new GridBagConstraints();
		gbc_panel.insets = new Insets(0, 0, 5, 5);
		gbc_panel.anchor = GridBagConstraints.NORTHWEST;
		gbc_panel.gridx = 0;
		gbc_panel.gridy = 0;
		add(panel, gbc_panel);

		connectButton = new JButton("Connect");
		connectButton.setEnabled(false);
		connectButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
			}
		});
		GridBagConstraints gbc_connectButton = new GridBagConstraints();
		gbc_connectButton.anchor = GridBagConstraints.WEST;
		gbc_connectButton.insets = new Insets(0, 0, 5, 5);
		gbc_connectButton.gridx = 0;
		gbc_connectButton.gridy = 1;
		add(connectButton, gbc_connectButton);

		// init icons
		greenCircle = createImageIcon("circle_green.png");
		redCircle = createImageIcon("circle_red.png");
		yellowCircle = createImageIcon("circle_yellow.png");

		// set icons to state labels
		serverStateIcon.setIcon(yellowCircle);
		connectionStateIcon.setIcon(redCircle);

		// set connection application listener
		if (applicationListener == null) {
			throw new NullPointerException("Application listener can't be null");
		}
		this.applicationListener = applicationListener;

		tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		GridBagConstraints gbc_tabbedPane = new GridBagConstraints();
		gbc_tabbedPane.gridwidth = 3;
		gbc_tabbedPane.insets = new Insets(0, 0, 0, 5);
		gbc_tabbedPane.fill = GridBagConstraints.BOTH;
		gbc_tabbedPane.gridx = 0;
		gbc_tabbedPane.gridy = 2;
		add(tabbedPane, gbc_tabbedPane);

		panel_1 = new JPanel();
		tabbedPane.addTab("Manage users", null, panel_1, null);
		panel_1.setLayout(new MigLayout("", "[250px:250px:250px][][][][]",
				"[][][][][]"));

		panel_2 = new JPanel();
		panel_1.add(panel_2, "flowx,cell 0 0 1 5,alignx left,growy");
		panel_2.setLayout(new BorderLayout(0, 0));

		filterField = new JTextField();
		panel_2.add(filterField, BorderLayout.NORTH);
		filterField.setColumns(14);
		filterField.addKeyListener(new FilterHandler());

		scrollPane = new JScrollPane();
		panel_2.add(scrollPane, BorderLayout.CENTER);

		list = new JList<RemoteUser>();
		list.setEnabled(false);
		list.setBackground(UIManager.getColor("Button.background"));
		list.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null,
				null));
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.getSelectionModel().addListSelectionListener(
				new ListSelectionHandler());
		scrollPane.setViewportView(list);

		btnAdd = new JButton("Add ...");
		btnAdd.setEnabled(false);
		btnAdd.addActionListener(new AddHandler());
		panel_1.add(btnAdd, "cell 1 1,growx,aligny top");

		btnDelete = new JButton("Delete");
		btnDelete.setEnabled(false);
		btnDelete.addActionListener(new DeleteHandler());
		panel_1.add(btnDelete, "cell 1 2,growx,aligny top");

		btnKick = new JButton("Kick");
		btnKick.setEnabled(false);
		btnKick.addActionListener(new KickHandler());
		panel_1.add(btnKick, "cell 1 3,growx,aligny top");

		panel_4 = new JPanel();
		tabbedPane.addTab("Manage server", null, panel_4, null);
		panel_4.setLayout(new MigLayout("", "[]", "[]"));

		btnShutdown = new JButton("Shutdown");
		btnShutdown.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				AdminpanelGui.this.applicationListener.shutdown();
			}
		});
		btnShutdown.setEnabled(false);
		panel_4.add(btnShutdown, "cell 0 0");

		// add button handler
		connectButton.addActionListener(new ConnectButtonHandler());

	}

	public void setAdminConsole(AdminsConsole adminConsole) {
		this.adminConsole = adminConsole;
	}

	/**
	 * 
	 * @param path
	 * @return
	 */
	private ImageIcon createImageIcon(String path) {
		URL url = getClass().getResource(path);
		if (url == null) {
			return null;
		} else {
			return new ImageIcon(url);
		}
	}

	/**
	 * 
	 */
	public void onDisconnectedFromServer() {
		connected = false;
		refreshGUI();
	}

	/**
	 * 
	 */
	public void onConnectedToServer() {
		connected = true;
		refreshGUI();
	}

	/**
	 * 
	 */
	public void onServerOnline() {
		serverOnline = true;
		refreshGUI();
	}

	/**
	 * 
	 */
	public void onServerOffline() {
		serverOnline = false;
		refreshGUI();
	}

	private void refreshGUI() {

		if (serverOnline) {
			serverStateText.setText("online");
			serverStateIcon.setIcon(greenCircle);
			connectButton.setEnabled(true);
		} else {
			serverStateText.setText("offline");
			serverStateIcon.setIcon(redCircle);
			connectButton.setEnabled(false);
		}

		if (connected) {
			connectionStateText.setText("connected");
			connectionStateIcon.setIcon(greenCircle);
			connectButton.setText("Disconnect");
		} else {
			connectionStateText.setText("not connected");
			connectionStateIcon.setIcon(redCircle);
			connectButton.setText("Connect");
		}

		filterField.setText("");
		filterField.setEnabled(connected);
		list.setEnabled(connected);
		btnAdd.setEnabled(connected);
		btnShutdown.setEnabled(connected);
	}

	/**
	 * 
	 */
	public void onServerNoinfo() {
		serverStateText.setText("unknown");
		serverStateIcon.setIcon(yellowCircle);
	}

	/**
	 * 
	 */
	public void onFailToConnect() {
		System.out.println("onFailToConnect");
	}

	protected JLabel getConnectionStateText() {
		return connectionStateText;
	}

	protected JLabel getConnectionIcon() {
		return connectionStateIcon;
	}

	protected JLabel getConnectionLabel() {
		return connectionLabel;
	}

	protected JLabel getServerStateText() {
		return serverStateText;
	}

	protected JLabel getStateIcon() {
		return serverStateIcon;
	}

	protected JLabel getStateLabel() {
		return stateLabel;
	}

	protected JButton getBtnNewButton() {
		return connectButton;
	}

	/**
	 * 
	 * @author doctorpro
	 * 
	 */
	private class KickHandler implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {

		}
	}

	/**
	 * 
	 * @author doctorpro
	 * 
	 */
	private class AddHandler implements ActionListener {

		private UserAddDialog d;

		public AddHandler() {
			d = new UserAddDialog();
			d.setResizable(false);
		}
		@Override
		public void actionPerformed(ActionEvent e) {

			d.setLocation(780, 640);
			d.pack();
			d.setVisible(true);
		}
	}

	private class UserAddDialog extends JDialog {

		private UserAddPanel panel;

		public UserAddDialog() {
			setModal(true);
			setTitle("Add user ...");

			panel = new UserAddPanel();
			setContentPane(panel);

			panel.getBtnAdd().addActionListener(new AddHandler());
			panel.getBtnCancel().addActionListener(new CancelHandler());
		}

		private class CancelHandler implements ActionListener {
			@Override
			public void actionPerformed(ActionEvent e) {
				UserAddDialog.this.setVisible(false);
				panel.getLoginField().setText("");
				panel.getPasswordField().setText("");
				panel.getConfirmPasswordField().setText("");
				setLocation(780, 640);
			}
		}

		private class AddHandler implements ActionListener {
			@Override
			public void actionPerformed(ActionEvent e) {

				String pass = new String(panel.getPasswordField().getPassword());
				String login = panel.getLoginField().getText();
				String errorMsg = "";

				if (login.equals("")) {
					errorMsg = checkHyphenation(errorMsg)
							+ "Login is not allowed to be empty.";
				}

				if (!checkLettersDigits(login)) {
					errorMsg = checkHyphenation(errorMsg)
							+ "Only letters and digits are allowed in login.";
				}

				if (pass.equals("")) {
					errorMsg = checkHyphenation(errorMsg)
							+ "Password cannot be empty.";
				} else if (!pass.equals(new String(panel
						.getConfirmPasswordField().getPassword()))) {
					errorMsg = checkHyphenation(errorMsg)
							+ "Passwords do not match.";
				}

				if (errorMsg.equals("")) {
					try {
						if (adminConsole.userExists(login)) {
							JOptionPane
									.showMessageDialog(
											null,
											"Login you entered has been already occupied.",
											"Illegal login",
											JOptionPane.ERROR_MESSAGE);
						} else {
							adminConsole.addUser(login, pass);
							panel.getLoginField().setText("");
							panel.getPasswordField().setText("");
							panel.getConfirmPasswordField().setText("");
							UserAddDialog.this.setVisible(false);
						}
					} catch (RemoteException ex) {
						ex.printStackTrace();
					} catch (ConsoleException ex) {
						ex.printStackTrace();
					}
				} else {
					JOptionPane.showMessageDialog(null,
							"Could not add new user because of "
									+ "the following:\n" + errorMsg,
							"Illegal input", JOptionPane.ERROR_MESSAGE);
				}
			}
		}
	}

	private static final String checkHyphenation(String s) {
		if (!s.equals("")) {
			return s + "\n";
		} else {
			return s;
		}
	}

	private static final boolean checkLettersDigits(String s) {
		for (int i = 0; i < s.length(); i++) {
			if (!Character.isAlphabetic(s.charAt(i))
					&& !Character.isDigit(s.charAt(i))) {
				return false;
			}
		}

		return true;
	}

	/**
	 * 
	 * @author doctorpro
	 * 
	 */
	private class DeleteHandler implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {

			if (list.getModel().getSize() == 0) {
				throw new IllegalStateException();
			}

			RemoteUser u = list.getSelectedValue();

			if (u == null) {
				throw new IllegalStateException();
			}

			int i = JOptionPane.showConfirmDialog(null,
					"Do you really want to delete user \"" + u.getLogin()
							+ "\"?");

			if (i == 0) {
				try {
					checkDeleteButton();
					adminConsole.removeUser(u.getLogin());
				} catch (RemoteException e1) {
					e1.printStackTrace();
				} catch (ConsoleException e1) {
					e1.printStackTrace();
				}
			}
		}
		
		/**
		 * 
		 */
		private void checkDeleteButton() {			
			if (list.getSelectedIndex() == list.getModel().getSize() - 1) {
				btnDelete.setEnabled(false);
			}			
		}
	}
	
	/**
	 * 
	 * @author doctorpro
	 * 
	 */
	private class ConnectButtonHandler implements ActionListener {

		private boolean applyConnectState = true;

		@Override
		public void actionPerformed(ActionEvent e) {

			if (applyConnectState) {
				JPasswordField passwordField = new JPasswordField(15);
				int action = JOptionPane.showConfirmDialog(null, passwordField,
						"Enter Password", JOptionPane.OK_CANCEL_OPTION);
				if (action == JOptionPane.OK_OPTION) {
					try {
						applicationListener.applyConnection(new String(
								passwordField.getPassword()));
						applyConnectState = !applyConnectState;
					} catch (ConsoleException e1) {
						JOptionPane.showMessageDialog(null,
								"Incorrect password");
					}
				}
			} else {
				applicationListener.applyDisconnection();
				applyConnectState = !applyConnectState;
			}
		}
	}

	/**
	 * 
	 * @param model
	 */
	public void setUserListModel(ListModel<RemoteUser> model, Filterable filterable) {
		list.setModel(model);
		this.filterable = filterable;
	}
	
	/**
	 * 
	 * @author doctorpro
	 *
	 */
	private class FilterHandler extends KeyAdapter {

		@Override
		public void keyReleased(KeyEvent arg0) {
			System.out.println("setting filter: " + filterField.getText());
			filterable.setFilter(filterField.getText());
		}		
	}

	/**
	 * 
	 * @author doctorpro
	 * 
	 */
	private class ListSelectionHandler implements ListSelectionListener {

		@Override
		public void valueChanged(ListSelectionEvent arg0) {
			RemoteUser u = list.getModel()
					.getElementAt(list.getSelectedIndex());
			btnDelete.setEnabled(true);
			if (u.isLoggedIn()) {
				btnKick.setEnabled(true);
			} else {
				btnKick.setEnabled(false);
			}
		}
	}
}

interface Filterable {
	public void setFilter(String s);
}
